/*
 * miniFreeRTOS SOC System emulation.
 *
 * Copyright (c) 2024- yanl1229@163.com.
 * Written by yanl1229
 *
 * This code is licensed under the GPL.
 */
#ifndef IRQ_H
#define IRQ_H

#include <stddef.h>
#include <stdint.h>

/* Interrupt control and state register */
#define NVIC_INT_CTRL_REG                 0xe000ed04
#define NVIC_SYSTICK_CTRL_REG             0xe000e010
#define NVIC_SYSTICK_LOAD_REG             0xe000e014
#define NVIC_SYSTICK_CURRENT_VALUE_REG    0xe000e018
#define NVIC_SHPR3_REG                    0xe000ed20

#define NVIC_PENDSVSET_BIT                (0x1 << 28)

#define NVIC_SYSTICK_CLK_BIT              (0x1 << 2)
#define NVIC_SYSTICK_INT_BIT              (0x1 << 1)
#define NVIC_SYSTICK_ENABLE_BIT           (0x1 << 0)

#define CONFIG_KERNEL_INTERRUPT_PRIORITY               (15 << 4)
#define CONFIG_MAX_SYSCALL_INTERRUPT_PRIORITY          (5 << 4)

#define NVIC_PENDSV_PRI                   (CONFIG_KERNEL_INTERRUPT_PRIORITY  << 16)
#define NVIC_SYSTICK_PRI                  (CONFIG_KERNEL_INTERRUPT_PRIORITY  << 24)


extern void disable_interrupt(void);
extern void enable_interrupt(void);
extern uint32_t interrupt_nest_count;

#ifdef __GNUC__
static inline void set_basepri(uint32_t basepri)
{
    __asm volatile
    (
        "	msr basepri, %0	    \n"\
        "	isb					\n"\
        "	dsb					\n"\
        ::"r" (basepri) : "memory"
    );
}

static inline uint32_t irq_save(void)
{
    uint32_t flags, temp;

    __asm volatile
    (
        "mrs %0, basepri  \n"\
        "mov %1, %2       \n"\
        "msr basepri, %1  \n"\
        "isb              \n"\
        "dsb              \n"\
        : "=r" (flags), "=r" (temp)
        : "i" (CONFIG_MAX_SYSCALL_INTERRUPT_PRIORITY)
        : "memory"
    );

    return flags;
}

static inline void irq_restore(uint32_t flags)
{
    __asm volatile
    (
        "msr basepri, %0 "::"r" (flags) : "memory"
    );
}

#else
static inline void set_basepri(uint32_t pri)
{
    __asm
    {
        msr basepri, pri
    }
}

static inline uint32_t irq_save(void)
{
    uint32_t flags, temp = CONFIG_MAX_SYSCALL_INTERRUPT_PRIORITY;

    __asm
    {
        mrs flags, basepri
        msr basepri, temp
        dsb
        isb
    }

    return flags;
}

static inline void irq_restore(uint32_t flags)
{
    __asm
    {
        msr basepri, flags
    }
}

#endif

static inline void irq_mask()
{
    set_basepri(CONFIG_MAX_SYSCALL_INTERRUPT_PRIORITY);
}

static inline void irq_unmask()
{
    set_basepri(0);
}

#define raw_readl(a)		(*(volatile uint32_t *)(a))
#define raw_writel(v,a)	    (*(volatile uint32_t *)(a) = (v))

#endif
